﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;


namespace CommonLib.PInvoke
{
	/// <summary>
	/// Defines the shape of hook procedures that can be called by the OpenFileDialog
	/// </summary>
	public delegate IntPtr OfnHookProc(IntPtr hWnd, UInt16 msg, Int32 wParam, Int32 lParam);

	/// <summary>
	/// Values that can be placed in the OPENFILENAME structure, we don't use all of them
	/// </summary>
	public enum OpenFileNameFlags : int
	{
		OFN_READONLY = 0X00000001,
		OFN_OVERWRITEPROMPT = 0X00000002,
		OFN_HIDEREADONLY = 0X00000004,
		OFN_NOCHANGEDIR = 0X00000008,
		OFN_SHOWHELP = 0X00000010,
		OFN_ENABLEHOOK = 0X00000020,
		OFN_ENABLETEMPLATE = 0X00000040,
		OFN_ENABLETEMPLATEHANDLE = 0X00000080,
		OFN_NOVALIDATE = 0X00000100,
		OFN_ALLOWMULTISELECT = 0X00000200,
		OFN_EXTENSIONDIFFERENT = 0X00000400,
		OFN_PATHMUSTEXIST = 0X00000800,
		OFN_FILEMUSTEXIST = 0X00001000,
		OFN_CREATEPROMPT = 0X00002000,
		OFN_SHAREAWARE = 0X00004000,
		OFN_NOREADONLYRETURN = 0X00008000,
		OFN_NOTESTFILECREATE = 0X00010000,
		OFN_NONETWORKBUTTON = 0X00020000,
		OFN_NOLONGNAMES = 0X00040000,
		OFN_EXPLORER = 0X00080000,
		OFN_NODEREFERENCELINKS = 0X00100000,
		OFN_LONGNAMES = 0X00200000,
		OFN_ENABLEINCLUDENOTIFY = 0X00400000,
		OFN_ENABLESIZING = 0X00800000,
		OFN_DONTADDTORECENT = 0X02000000,
		OFN_FORCESHOWHIDDEN = 0X10000000
	};

	/// <summary>
	/// Values that can be placed in the FlagsEx field of the OPENFILENAME structure
	/// </summary>
	public class OpenFileNameFlagsEx
	{
		public const Int32 NoPlacesBar = 0x00000001;
	};

	/// <summary>
	/// The possible notification messages that can be generated by the OpenFileDialog
	/// We only look for CDN_SELCHANGE
	/// </summary>
	public enum CommonDlgNotification : ushort
	{
		CDN_FIRST   = unchecked((UInt16)((UInt16)0 - (UInt16)601)),
		CDN_LAST    = unchecked((UInt16)((UInt16)0 - (UInt16)699)),

		CDN_INITDONE = (CDN_FIRST - 0X0000),
		CDN_SELCHANGE = (CDN_FIRST - 0X0001),
		CDN_FOLDERCHANGE = (CDN_FIRST - 0X0002),
		CDN_SHAREVIOLATION = (CDN_FIRST - 0X0003),
		CDN_HELP = (CDN_FIRST - 0X0004),
		CDN_FILEOK = (CDN_FIRST - 0X0005),
		CDN_TYPECHANGE = (CDN_FIRST - 0X0006),
		CDN_INCLUDEITEM = (CDN_FIRST - 0X0007)
	}

	/// <summary>
	/// Messages that can be send to the common dialogs
	/// We only use CDM_GETFILEPATH
	/// </summary>
	public enum DialogChangeProperties
	{
		CDM_FIRST = (WindowMessage.WM_USER + 100),
		CDM_GETSPEC = (CDM_FIRST + 0x0000),
		CDM_GETFILEPATH = (CDM_FIRST + 0x0001),
		CDM_GETFOLDERPATH = (CDM_FIRST + 0x0002),
		CDM_GETFOLDERIDLIST = (CDM_FIRST + 0x0003),
		CDM_SETCONTROLTEXT = (CDM_FIRST + 0x0004),
		CDM_HIDECONTROL = (CDM_FIRST + 0x0005),
		CDM_SETDEFEXT = (CDM_FIRST + 0x0006)
	}

	///// <summary>
	///// See the documentation for OPENFILENAME
	///// </summary>
	//[StructLayout(LayoutKind.Sequential)]
	//public struct OpenFileName
	//{
	//    public Int32 lStructSize;
	//    public IntPtr hwndOwner;
	//    public IntPtr hInstance;
	//    public IntPtr lpstrFilter;
	//    public IntPtr lpstrCustomFilter;
	//    public Int32 nMaxCustFilter;
	//    public Int32 nFilterIndex;
	//    public IntPtr lpstrFile;
	//    public Int32 nMaxFile;
	//    public IntPtr lpstrFileTitle;
	//    public Int32 nMaxFileTitle;
	//    public IntPtr lpstrInitialDir;
	//    public IntPtr lpstrTitle;
	//    public OpenFileNameFlags Flags;
	//    public Int16 nFileOffset;
	//    public Int16 nFileExtension;
	//    public IntPtr lpstrDefExt;
	//    public Int32 lCustData;
	//    public OfnHookProc lpfnHook;
	//    public IntPtr lpTemplateName;
	//    public IntPtr pvReserved;
	//    public Int32 dwReserved;
	//    public Int32 FlagsEx;
	//};

	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
	public struct OPENFILENAME
	{
		public int lStructSize;
		public IntPtr hwndOwner;
		public int hInstance;
		[MarshalAs(UnmanagedType.LPTStr)]
		public string lpstrFilter;
		[MarshalAs(UnmanagedType.LPTStr)]
		public string lpstrCustomFilter;
		public int nMaxCustFilter;
		public int nFilterIndex;
		[MarshalAs(UnmanagedType.LPTStr)]
		public string lpstrFile;
		public int nMaxFile;
		[MarshalAs(UnmanagedType.LPTStr)]
		public string lpstrFileTitle;
		public int nMaxFileTitle;
		[MarshalAs(UnmanagedType.LPTStr)]
		public string lpstrInitialDir;
		[MarshalAs(UnmanagedType.LPTStr)]
		public string lpstrTitle;
		public OpenFileNameFlags Flags;
		public short nFileOffset;
		public short nFileExtension;
		[MarshalAs(UnmanagedType.LPTStr)]
		public string lpstrDefExt;
		public int lCustData;
		public OfnHookProc lpfnHook;
		[MarshalAs(UnmanagedType.LPTStr)]
		public string lpTemplateName;
		//only if on nt 5.0 or higher
		public int pvReserved;
		public int dwReserved;
		public int FlagsEx;
	}

	/// <summary>
	/// Part of the notification messages sent by the common dialogs
	/// </summary>
	[StructLayout(LayoutKind.Sequential)]
	public struct NMHDR
	{
		public IntPtr hWndFrom;
		public IntPtr idFrom;
		public UInt16 code;
	};

	/// <summary>
	/// Part of the notification messages sent by the common dialogs
	/// </summary>
	[StructLayout(LayoutKind.Explicit)]
	public struct OFNOTIFY
	{
		[FieldOffset(0)]
		public NMHDR hdr;
		[FieldOffset(12)]
		public IntPtr ipOfn;
		[FieldOffset(16)]
		public IntPtr ipFile;
	};

	/// <summary>
	/// Win32 window style constants
	/// We use them to set up our child window
	/// </summary>
	public class DlgStyle
	{
		public const Int32 DsSetFont = 0x00000040;
		public const Int32 Ds3dLook = 0x00000004;
		public const Int32 DsControl = 0x00000400;
		public const Int32 WsChild = 0x40000000;
		public const Int32 WsClipSiblings = 0x04000000;
		public const Int32 WsVisible = 0x10000000;
		public const Int32 WsGroup = 0x00020000;
		public const Int32 SsNotify = 0x00000100;
	};

	/// <summary>
	/// Win32 "extended" window style constants
	/// </summary>
	public class ExStyle
	{
		public const Int32 WsExNoParentNotify = 0x00000004;
		public const Int32 WsExControlParent = 0x00010000;
	};

	/// <summary>
	/// An in-memory Win32 dialog template
	/// Note: this has a very specific structure with a single static "label" control
	/// See documentation for DLGTEMPLATE and DLGITEMTEMPLATE
	/// </summary>
	//[StructLayout(LayoutKind.Sequential)]
	//public class DLGTEMPLATE
	//{
	//    // The dialog template - see documentation for DLGTEMPLATE
	//    public Int32 style = DlgStyle.Ds3dLook | DlgStyle.DsControl | DlgStyle.WsChild | DlgStyle.WsClipSiblings | DlgStyle.SsNotify;
	//    public Int32 extendedStyle = ExStyle.WsExControlParent;
	//    public Int16 numItems = 1;
	//    public Int16 x = 0;
	//    public Int16 y = 0;
	//    public Int16 cx = 0;
	//    public Int16 cy = 0;
	//    public Int16 reservedMenu = 0;
	//    public Int16 reservedClass = 0;
	//    public Int16 reservedTitle = 0;

	//    // Single dlg item, must be dword-aligned - see documentation for DLGITEMTEMPLATE
	//    public Int32 itemStyle = DlgStyle.Ds3dLook | DlgStyle.DsControl | DlgStyle.WsChild | DlgStyle.WsClipSiblings | DlgStyle.SsNotify;
	//    public Int32 itemExtendedStyle = ExStyle.WsExNoParentNotify;
	//    public Int16 itemX = 0;
	//    public Int16 itemY = 0;
	//    public Int16 itemCx = 0;
	//    public Int16 itemCy = 0;
	//    public Int16 itemId = 1134; //any number
	//    public UInt16 itemClassHdr = 0xffff;	// we supply a constant to indicate the class of this control
	//    public Int16 itemClass = 0x0082;	// static label control
	//    public Int16 itemText = 0x0000;	// no text for this control
	//    public Int16 itemData = 0x0000;	// no creation data for this control
	//};

	public class ComDlg32
	{
		[DllImport("Comdlg32.dll", CharSet = CharSet.Auto, SetLastError = true)]
		public static extern bool GetOpenFileName(ref OPENFILENAME lpofn);

		[DllImport("ComDlg32.dll", CharSet = CharSet.Auto)]
		public static extern Int32 CommDlgExtendedError();
	}
}
